home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / waisgate / HTFile.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  25KB  |  949 lines

  1. /*            File Access                HTFile.c
  2. **            ===========
  3. **
  4. **    This is unix-specific code in general, with some VMS bits.
  5. **    These are routines for file access used by WWW browsers.
  6. **
  7. ** History:
  8. **       Feb 91    Written Tim Berners-Lee CERN/CN
  9. **       Apr 91    vms-vms access included using DECnet syntax
  10. **    26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
  11. **            Fixed access bug for relative names on VMS.
  12. **
  13. ** Bugs:
  14. **    FTP: Cannot access VMS files from a unix machine.
  15. **      How can we know that the
  16. **    target machine runs VMS?
  17. **
  18. **    DIRECTORIES are NOT SORTED.. alphabetically etc.
  19. */
  20.  
  21. #include "HTFile.h"        /* Implemented here */
  22.  
  23.  
  24. #define INFINITY 512        /* file name length @@ FIXME */
  25. #define MULTI_SUFFIX ".multi"   /* Extension for scanning formats */
  26.  
  27. #include <sys/fcntl.h>
  28. #include <sys/types.h>
  29. #include <dirent.h>
  30.  
  31. #ifdef _M_UNIX  /* for sco */
  32. #define   d_namlen  d_reclen
  33. #define NO_GROUPS
  34. #endif
  35.  
  36. #include "HTUtils.h"
  37.  
  38. #include "HTParse.h"
  39. #include "tcp.h"
  40. #include "HTTCP.h"
  41. #ifndef DECNET
  42. #include "HTFTP.h"
  43. #endif
  44. #include "HTAnchor.h"
  45. #include "HTAtom.h"
  46. #include "HTWriter.h"
  47. #include "HTFWriter.h"
  48. #include "HTInit.h"
  49.  
  50. typedef struct _HTSuffix {
  51.     char *        suffix;
  52.     HTAtom *    rep;
  53.     float        quality;
  54. } HTSuffix;
  55.  
  56.  
  57.  
  58. #ifdef unix            /* if this is to compile on a UNIX machine */
  59. #include "HTML.h"        /* For directory object building */
  60.  
  61. #define PUTC(c) (*targetClass.put_character)(target, c)
  62. #define PUTS(s) (*targetClass.put_string)(target, s)
  63. #define START(e) (*targetClass.start_element)(target, e, 0, 0)
  64. #define END(e) (*targetClass.end_element)(target, e)
  65. #define END_TARGET (*targetClass.end_document)(target)
  66. #define FREE_TARGET (*targetClass.free)(target)
  67. struct _HTStructured {
  68.     CONST HTStructuredClass *    isa;
  69.     /* ... */
  70. };
  71.  
  72. #endif                /* unix */
  73.  
  74.  
  75. /*                   Controlling globals
  76. **
  77. */
  78.  
  79. PUBLIC int HTDirAccess = HT_DIR_OK;
  80. PUBLIC int HTDirReadme = HT_DIR_README_TOP;
  81.  
  82. PRIVATE char *HTMountRoot = "/net/";        /* Where to find mounts */
  83. #ifdef vms
  84. PRIVATE char *HTCacheRoot = "/WWW$SCRATCH/";   /* Where to cache things */
  85. #else
  86. PRIVATE char *HTCacheRoot = "/tmp/W3_Cache_";   /* Where to cache things */
  87. #endif
  88.  
  89. /* PRIVATE char *HTSaveRoot  = "$(HOME)/WWW/";*/    /* Where to save things */
  90.  
  91.  
  92. /*    Suffix registration
  93. */
  94.  
  95. PRIVATE HTList * HTSuffixes = 0;
  96.  
  97. /*    Define the representation associated with a file suffix
  98. **    -------------------------------------------------------
  99. */
  100. PUBLIC void HTSetSuffix ARGS3(
  101.     CONST char *,    suffix,
  102.     CONST char *,    representation,
  103.     float,        value)
  104. {
  105.     
  106.     HTSuffix * suff = (HTSuffix*) calloc(1, sizeof(HTSuffix));
  107.     if (suff == NULL) outofmem(__FILE__, "HTSetSuffix");
  108.     
  109.     if (!HTSuffixes) HTSuffixes = HTList_new();
  110.     
  111.     StrAllocCopy(suff->suffix, suffix);
  112.     suff->rep = HTAtom_for(representation);
  113.     suff->quality = value;
  114.     HTList_addObject(HTSuffixes, suff);
  115. }
  116.  
  117.  
  118.  
  119.  
  120. #ifdef vms
  121. /*    Convert unix-style name into VMS name
  122. **    -------------------------------------
  123. **
  124. ** Bug:    Returns pointer to static -- non-reentrant
  125. */
  126. PRIVATE char * vms_name(CONST char * nn, CONST char * fn)
  127. {
  128.  
  129. /*    We try converting the filename into Files-11 syntax. That is, we assume
  130. **    first that the file is, like us, on a VMS node. We try remote
  131. **    (or local) DECnet access. Files-11, VMS, VAX and DECnet
  132. **    are trademarks of Digital Equipment Corporation. 
  133. **    The node is assumed to be local if the hostname WITHOUT DOMAIN
  134. **    matches the local one. @@@
  135. */
  136.     static char vmsname[INFINITY];    /* returned */
  137.     char * filename = (char*)malloc(strlen(fn)+1);
  138.     char * nodename = (char*)malloc(strlen(nn)+2+1);    /* Copies to hack */
  139.     char *second;        /* 2nd slash */
  140.     char *last;            /* last slash */
  141.     
  142.     char * hostname = HTHostName();
  143.  
  144.     if (!filename || !nodename) outofmem(__FILE__, "vms_name");
  145.     strcpy(filename, fn);
  146.     strcpy(nodename, "");    /* On same node? Yes if node names match */
  147.     {
  148.         char *p, *q;
  149.         for (p=hostname, q=nn; *p && *p!='.' && *q && *q!='.'; p++, q++){
  150.         if (TOUPPER(*p)!=TOUPPER(*q)) {
  151.             strcpy(nodename, nn);
  152.         q = strchr(nodename, '.');    /* Mismatch */
  153.         if (q) *q=0;            /* Chop domain */
  154.         strcat(nodename, "::");        /* Try decnet anyway */
  155.         break;
  156.         }
  157.     }
  158.     }
  159.  
  160.     second = strchr(filename+1, '/');        /* 2nd slash */
  161.     last = strrchr(filename, '/');    /* last slash */
  162.         
  163.     if (!second) {                /* Only one slash */
  164.     sprintf(vmsname, "%s%s", nodename, filename + 1);
  165.     } else if(second==last) {        /* Exactly two slashes */
  166.     *second = 0;        /* Split filename from disk */
  167.     sprintf(vmsname, "%s%s:%s", nodename, filename+1, second+1);
  168.     *second = '/';    /* restore */
  169.     } else {                 /* More than two slashes */
  170.     char * p;
  171.     *second = 0;        /* Split disk from directories */
  172.     *last = 0;        /* Split dir from filename */
  173.     sprintf(vmsname, "%s%s:[%s]%s",
  174.         nodename, filename+1, second+1, last+1);
  175.     *second = *last = '/';    /* restore filename */
  176.     for (p=strchr(vmsname, '['); *p!=']'; p++)
  177.         if (*p=='/') *p='.';    /* Convert dir sep.  to dots */
  178.     }
  179.     free(nodename);
  180.     free(filename);
  181.     return vmsname;
  182. }
  183.  
  184.  
  185. #endif /* vms */
  186.  
  187.  
  188.  
  189. /*    Send README file
  190. **
  191. **  If a README file exists, then it is inserted into the document here.
  192. */
  193.  
  194. #ifdef unix
  195. PRIVATE void do_readme ARGS2(HTStructured *, target, CONST char *, localname)
  196.     FILE * fp;
  197.     char * readme_file_name = 
  198.     malloc(strlen(localname)+ 1 + strlen(HT_DIR_README_FILE) + 1);
  199.     strcpy(readme_file_name, localname);
  200.     strcat(readme_file_name, "/");
  201.     strcat(readme_file_name, HT_DIR_README_FILE);
  202.     
  203.     fp = fopen(readme_file_name,  "r");
  204.     
  205.     if (fp) {
  206.     HTStructuredClass targetClass;
  207.     
  208.     targetClass =  *target->isa;    /* (Can't init agregate in K&R) */
  209.     START(HTML_PRE);
  210.     for(;;){
  211.         char c = fgetc(fp);
  212.         if (c == (char)EOF) break;
  213.         switch (c) {
  214.             case '&':
  215.         case '<':
  216.         case '>':
  217.             PUTC('&');
  218.             PUTC('#');
  219.             PUTC((char)(c / 10));
  220.             PUTC((char) (c % 10));
  221.             PUTC(';');
  222.             break;
  223.             case '\n':
  224.             PUTC('\r');    /* Fall through */
  225.         default:
  226.             PUTC(c);
  227.         }
  228.     }
  229.     END(HTML_PRE);
  230.     fclose(fp);
  231.     } 
  232. }
  233. #endif
  234.  
  235.  
  236. /*    Make the cache file name for a W3 document
  237. **    ------------------------------------------
  238. **    Make up a suitable name for saving the node in
  239. **
  240. **    E.g.    /tmp/WWW_Cache_news/1234@cernvax.cern.ch
  241. **        /tmp/WWW_Cache_http/crnvmc/FIND/xx.xxx.xx
  242. **
  243. ** On exit,
  244. **    returns    a malloc'ed string which must be freed by the caller.
  245. */
  246. PUBLIC char * HTCacheFileName ARGS1(CONST char *,name)
  247. {
  248.     char * access = HTParse(name, "", PARSE_ACCESS);
  249.     char * host = HTParse(name, "", PARSE_HOST);
  250.     char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
  251.     
  252.     char * result;
  253.     result = (char *)malloc(
  254.         strlen(HTCacheRoot)+strlen(access)
  255.         +strlen(host)+strlen(path)+6+1);
  256.     if (result == NULL) outofmem(__FILE__, "HTCacheFileName");
  257.     sprintf(result, "%s/WWW/%s/%s%s", HTCacheRoot, access, host, path);
  258.     free(path);
  259.     free(access);
  260.     free(host);
  261.     return result;
  262. }
  263.  
  264.  
  265. /*    Open a file for write, creating the path
  266. **    ----------------------------------------
  267. */
  268. #ifdef NOT_IMPLEMENTED
  269. PRIVATE int HTCreatePath ARGS1(CONST char *,path)
  270. {
  271.     return -1;
  272. }
  273. #endif
  274.  
  275. /*    Convert filenames between local and WWW formats
  276. **    -----------------------------------------------
  277. **    Make up a suitable name for saving the node in
  278. **
  279. **    E.g.    $(HOME)/WWW/news/1234@cernvax.cern.ch
  280. **        $(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx
  281. **
  282. ** On exit,
  283. **    returns    a malloc'ed string which must be freed by the caller.
  284. */
  285. static char * HTLocalName ARGS1(CONST char *,name)
  286. {
  287.     char * access = HTParse(name, "", PARSE_ACCESS);
  288.     char * host = HTParse(name, "", PARSE_HOST);
  289.     char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
  290.    
  291.     HTUnEscape(path);    /* Interpret % signs */
  292.     
  293.     if (0==strcmp(access, "file")) {
  294.         free(access);    
  295.     if ((0==strcmp(host, HTHostName())) || !*host) {
  296.         free(host);
  297.         if (TRACE) fprintf(stderr, "Node `%s' means path `%s'\n", name, path);
  298.         return(path);
  299.     } else {
  300.         char * result = (char *)malloc(
  301.                     strlen("/Net/")+strlen(host)+strlen(path)+1);
  302.               if (result == NULL) outofmem(__FILE__, "HTLocalName");
  303.         sprintf(result, "%s%s%s", "/Net/", host, path);
  304.         free(host);
  305.         free(path);
  306.         if (TRACE) fprintf(stderr, "Node `%s' means file `%s'\n", name, result);
  307.         return result;
  308.     }
  309.     } else {  /* other access */
  310.     char * result;
  311.         CONST char * home =  (CONST char*)getenv("HOME");
  312.     if (!home) home = "/tmp"; 
  313.     result = (char *)malloc(
  314.         strlen(home)+strlen(access)+strlen(host)+strlen(path)+6+1);
  315.       if (result == NULL) outofmem(__FILE__, "HTLocalName");
  316.     sprintf(result, "%s/WWW/%s/%s%s", home, access, host, path);
  317.     free(path);
  318.     free(access);
  319.     free(host);
  320.     return result;
  321.     }
  322. }
  323.  
  324.  
  325. /*    Make a WWW name from a full local path name
  326. **
  327. ** Bugs:
  328. **    At present, only the names of two network root nodes are hand-coded
  329. **    in and valid for the NeXT only. This should be configurable in
  330. **    the general case.
  331. */
  332.  
  333. PUBLIC char * WWW_nameOfFile ARGS1 (CONST char *,name)
  334. {
  335.     char * result;
  336. #ifdef NeXT
  337.     if (0==strncmp("/private/Net/", name, 13)) {
  338.     result = (char *)malloc(7+strlen(name+13)+1);
  339.     if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
  340.     sprintf(result, "file://%s", name+13);
  341.     } else
  342. #endif
  343.     if (0==strncmp(HTMountRoot, name, 5)) {
  344.     result = (char *)malloc(7+strlen(name+5)+1);
  345.     if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
  346.     sprintf(result, "file://%s", name+5);
  347.     } else {
  348.         result = (char *)malloc(7+strlen(HTHostName())+strlen(name)+1);
  349.     if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
  350.     sprintf(result, "file://%s%s", HTHostName(), name);
  351.     }
  352.     if (TRACE) fprintf(stderr, "File `%s'\n\tmeans node `%s'\n", name, result);
  353.     return result;
  354. }
  355.  
  356.  
  357. /*    Determine a suitable suffix, given the representation
  358. **    -----------------------------------------------------
  359. **
  360. ** On entry,
  361. **    rep    is the atomized MIME style representation
  362. **
  363. ** On exit,
  364. **    returns    a pointer to a suitable suffix string if one has been
  365. **        found, else "".
  366. */
  367. PUBLIC CONST char * HTFileSuffix ARGS1(HTAtom*, rep)
  368. {
  369.     HTSuffix * suff;
  370.     int n;
  371.     int i;
  372.  
  373. #ifndef NO_INIT    
  374.     if (!HTSuffixes) HTFileInit();
  375. #endif
  376.     n = HTList_count(HTSuffixes);
  377.     for(i=0; i<n; i++) {
  378.     suff = HTList_objectAt(HTSuffixes, i);
  379.     if (suff->rep == rep) {
  380.         return suff->suffix;        /* OK -- found */
  381.     }
  382.     }
  383.     return "";        /* Dunno */
  384. }
  385.  
  386.  
  387. /*    Determine file format from file name
  388. **    ------------------------------------
  389. **
  390. */
  391.  
  392. PUBLIC HTFormat HTFileFormat ARGS1 (CONST char *,filename)
  393.  
  394. {
  395.     HTSuffix * suff;
  396.     int n;
  397.     int i;
  398.     int lf = strlen(filename);
  399.  
  400. #ifndef NO_INIT    
  401.     if (!HTSuffixes) HTFileInit();
  402. #endif
  403.     n = HTList_count(HTSuffixes);
  404.     for(i=0; i<n; i++) {
  405.         int ls;
  406.     suff = HTList_objectAt(HTSuffixes, i);
  407.     ls = strlen(suff->suffix);
  408.     if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) {
  409.         return suff->rep;        /* OK -- found */
  410.     }
  411.     }
  412.     return strchr(filename, '.') ? WWW_BINARY : WWW_PLAINTEXT;    /* Dunno */
  413. }
  414.  
  415.  
  416. /*    Determine value from file name
  417. **    ------------------------------
  418. **
  419. */
  420.  
  421. PUBLIC float HTFileValue ARGS1 (CONST char *,filename)
  422.  
  423. {
  424.     HTSuffix * suff;
  425.     int n;
  426.     int i;
  427.     int lf = strlen(filename);
  428.  
  429. #ifndef NO_INIT    
  430.     if (!HTSuffixes) HTFileInit();
  431. #endif
  432.     n = HTList_count(HTSuffixes);
  433.     for(i=0; i<n; i++) {
  434.         int ls;
  435.     suff = HTList_objectAt(HTSuffixes, i);
  436.     ls = strlen(suff->suffix);
  437.     if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) {
  438.         if (TRACE) fprintf(stderr, "File: Value of %s is %.3f\n",
  439.                    filename, suff->quality);
  440.         return suff->quality;        /* OK -- found */
  441.     }
  442.     }
  443.     return 0.3;        /* Dunno! */
  444. }
  445.  
  446.  
  447. /*    Determine write access to a file
  448. **    --------------------------------
  449. **
  450. ** On exit,
  451. **    return value    YES if file can be accessed and can be written to.
  452. **
  453. ** Bugs:
  454. **    1.    No code for non-unix systems.
  455. **    2.    Isn't there a quicker way?
  456. */
  457.  
  458. #ifdef vms
  459. #define NO_GROUPS
  460. #endif
  461. #ifdef NO_UNIX_IO
  462. #define NO_GROUPS
  463. #endif
  464. #ifdef PCNFS
  465. #define NO_GROUPS
  466. #endif
  467.  
  468. PUBLIC BOOL HTEditable ARGS1 (CONST char *,filename)
  469. {
  470. #ifdef NO_GROUPS
  471.     return NO;        /* Safe answer till we find the correct algorithm */
  472. #else
  473.     int     groups[NGROUPS];    
  474.     uid_t    myUid;
  475.     int        ngroups;            /* The number of groups  */
  476.     struct stat    fileStatus;
  477.     int        i;
  478.         
  479.     if (stat(filename, &fileStatus))        /* Get details of filename */
  480.         return NO;                /* Can't even access file! */
  481.  
  482.     ngroups = getgroups(NGROUPS, groups);    /* Groups to which I belong  */
  483.     myUid = geteuid();                /* Get my user identifier */
  484.  
  485.     if (TRACE) {
  486.         int i;
  487.     printf("File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
  488.             (unsigned int) fileStatus.st_mode, fileStatus.st_uid,
  489.         fileStatus.st_gid,
  490.         myUid, ngroups);
  491.     for (i=0; i<ngroups; i++) printf(" %d", groups[i]);
  492.     printf(")\n");
  493.     }
  494.     
  495.     if (fileStatus.st_mode & 0002)        /* I can write anyway? */
  496.         return YES;
  497.     
  498.     if ((fileStatus.st_mode & 0200)        /* I can write my own file? */
  499.      && (fileStatus.st_uid == myUid))
  500.         return YES;
  501.  
  502.     if (fileStatus.st_mode & 0020)        /* Group I am in can write? */
  503.     {
  504.        for (i=0; i<ngroups; i++) {
  505.             if (groups[i] == fileStatus.st_gid)
  506.             return YES;
  507.     }
  508.     }
  509.     if (TRACE) fprintf(stderr, "\tFile is not editable.\n");
  510.     return NO;                    /* If no excuse, can't do */
  511. #endif
  512. }
  513.  
  514.  
  515. /*    Make a save stream
  516. **    ------------------
  517. **
  518. **    The stream must be used for writing back the file.
  519. **    @@@ no backup done
  520. */
  521. PUBLIC HTStream * HTFileSaveStream ARGS1(HTParentAnchor *, anchor)
  522. {
  523.  
  524.     CONST char * addr = HTAnchor_address((HTAnchor*)anchor);
  525.     char *  localname = HTLocalName(addr);
  526.     
  527.     FILE* fp = fopen(localname, "w");
  528.     if (!fp) return NULL;
  529.     
  530.     return HTFWriter_new(fp);
  531.     
  532. }
  533.  
  534.  
  535. /*    Load a document
  536. **    ---------------
  537. **
  538. ** On entry,
  539. **    addr        must point to the fully qualified hypertext reference.
  540. **            This is the physsical address of the file
  541. **
  542. ** On exit,
  543. **    returns        <0        Error has occured.
  544. **            HTLOADED    OK 
  545. **
  546. */
  547. PUBLIC int HTLoadFile ARGS4 (
  548.     CONST char *,        addr,
  549.     HTParentAnchor *,    anchor,
  550.     HTFormat,        format_out,
  551.     HTStream *,        sink
  552. )
  553. {
  554.     char * filename;
  555.     HTFormat format;
  556.     int fd = -1;        /* Unix file descriptor number = INVALID */
  557.     char * nodename = 0;
  558.     char * newname=0;    /* Simplified name of file */
  559.  
  560. /*    Reduce the filename to a basic form (hopefully unique!)
  561. */
  562.     StrAllocCopy(newname, addr);
  563.     filename=HTParse(newname, "", PARSE_PATH|PARSE_PUNCTUATION);
  564.     nodename=HTParse(newname, "", PARSE_HOST);
  565.     free(newname);
  566. /*printf("HTLoadFile filename %s\n",filename); /* hess */
  567.     format = HTFileFormat(filename);
  568.  
  569.  
  570.     
  571. #ifdef vms
  572. /* Assume that the file is in Unix-style syntax if it contains a '/'
  573.    after the leading one @@ */
  574.     {
  575.     char * vmsname = strchr(filename + 1, '/') ?
  576.       vms_name(nodename, filename) : filename + 1;
  577.     fd = open(vmsname, O_RDONLY, 0);
  578.     
  579. /*    If the file wasn't VMS syntax, then perhaps it is ultrix
  580. */
  581.     if (fd<0) {
  582.         char ultrixname[INFINITY];
  583.         if (TRACE) fprintf(stderr, "HTFile: Can't open as %s\n", vmsname);
  584.         sprintf(ultrixname, "%s::\"%s\"", nodename, filename);
  585.         fd = open(ultrixname, O_RDONLY, 0);
  586.         if (fd<0) {
  587.         if (TRACE) fprintf(stderr, 
  588.                    "HTFile: Can't open as %s\n", ultrixname);
  589.         }
  590.     }
  591.     }
  592. #else
  593.  
  594.     free(filename);
  595.     
  596. /*    For unix, we try to translate the name into the name of a transparently
  597. **    mounted file.
  598. **
  599. **    Not allowed in secure (HTClienntHost) situations TBL 921019
  600. */
  601. #ifndef NO_UNIX_IO
  602.     /* @@@@ Need protection here for telnet server but not httpd server */
  603.      
  604.     /* if (!HTClientHost) */ {        /* try local unix file system */
  605.     /* this was mapping a file name 
  606.      * that was already mapped ?? !!     hess
  607.     char * localname = HTLocalName(addr); 
  608.      */
  609.     char * localname = addr; 
  610.     struct stat dir_info;
  611.     
  612. #ifdef GOT_READ_DIR
  613.  
  614. /*              Multiformat handling
  615. **
  616. **    If needed, scan directory to find a good file.
  617. **  Bug:  we don't stat the file to find the length
  618. */
  619.     if ( (strlen(localname) > strlen(MULTI_SUFFIX))
  620.        && (0==strcmp(localname + strlen(localname) - strlen(MULTI_SUFFIX),
  621.                       MULTI_SUFFIX))) {
  622.         DIR *dp;
  623.         struct direct * dirbuf;
  624.  
  625.         float best = NO_VALUE_FOUND;    /* So far best is bad */
  626.         HTFormat best_rep = NULL;    /* Set when rep found */
  627.         struct direct best_dirbuf;    /* Best dir entry so far */
  628.  
  629.         char * base = strrchr(localname, '/');
  630.         int baselen;
  631.  
  632.         if (!base || base == localname) goto forget_multi;
  633.         *base++ = 0;        /* Just got directory name */
  634.         baselen = strlen(base)- strlen(MULTI_SUFFIX);
  635.         base[baselen] = 0;    /* Chop off suffix */
  636.  
  637.         dp = opendir(localname);
  638.         if (!dp) {
  639. forget_multi:
  640.         free(localname);
  641.         return HTLoadError(sink, 500,
  642.             "Multiformat: directory scan failed.");
  643.         }
  644.         
  645.         while (dirbuf = readdir(dp)) {
  646.             /* while there are directory entries to be read */
  647.         if (dirbuf->d_ino == 0) continue;
  648.                 /* if the entry is not being used, skip it */
  649.         
  650.         if (dirbuf->d_namlen > baselen &&      /* Match? */
  651.             !strncmp(dirbuf->d_name, base, baselen)) {    
  652.             HTFormat rep = HTFileFormat(dirbuf->d_name);
  653.             float value = HTStackValue(rep, format_out,
  654.                             HTFileValue(dirbuf->d_name),
  655.                         0.0  /* @@@@@@ */);
  656.             if (value != NO_VALUE_FOUND) {
  657.                 if (TRACE) fprintf(stderr,
  658.                 "HTFile: value of presenting %s is %f\n",
  659.                 HTAtom_name(rep), value);
  660.             if  (value > best) {
  661.                 best_rep = rep;
  662.                 best = value;
  663.                 best_dirbuf = *dirbuf;
  664.                }
  665.             }    /* if best so far */             
  666.          } /* if match */  
  667.             
  668.         } /* end while directory entries left to read */
  669.         closedir(dp);
  670.         
  671.         if (best_rep) {
  672.         format = best_rep;
  673.         base[-1] = '/';        /* Restore directory name */
  674.         base[0] = 0;
  675.         StrAllocCat(localname, best_dirbuf.d_name);
  676.         goto open_file;
  677.         
  678.         } else {             /* If not found suitable file */
  679.         free(localname);
  680.         return HTLoadError(sink, 403,    /* List formats? */
  681.            "Could not find suitable representation for transmission.");
  682.         }
  683.         /*NOTREACHED*/
  684.     } /* if multi suffix */
  685. /*
  686. **    Check to see if the 'localname' is in fact a directory.  If it is
  687. **    create a new hypertext object containing a list of files and 
  688. **    subdirectories contained in the directory.  All of these are links
  689. **      to the directories or files listed.
  690. **      NB This assumes the existance of a type 'struct direct', which will
  691. **      hold the directory entry, and a type 'DIR' which is used to point to
  692. **      the current directory being read.
  693. */
  694.     
  695. /*printf("HTLoadFile localname %s\n",localname); /* hess */
  696.     
  697.     if (stat(localname,&dir_info) == -1) {     /* get file information */
  698.                                    /* if can't read file information */
  699.         if (TRACE) fprintf(stderr, "HTFile: can't stat %s\n", localname);
  700.  
  701.     }  else {        /* Stat was OK */
  702.         
  703.  
  704.         if (((dir_info.st_mode) & S_IFMT) == S_IFDIR) {
  705.         /* if localname is a directory */    
  706.  
  707.         HTStructured* target;        /* HTML object */
  708.         HTStructuredClass targetClass;
  709.  
  710.         DIR *dp;
  711.         struct direct * dirbuf;
  712.         
  713.         char * logical;
  714.         char * tail;
  715.         
  716.         BOOL present[HTML_A_ATTRIBUTES];
  717.         char * value[HTML_A_ATTRIBUTES];
  718.         
  719.         char * tmpfilename = NULL;
  720.         struct stat file_info;
  721.         
  722.         if (TRACE)
  723.             fprintf(stderr,"%s is a directory\n",localname);
  724.             
  725. /*    Check directory access.
  726. **    Selective access means only those directories containing a
  727. **    marker file can be browsed
  728. */
  729.         if (HTDirAccess == HT_DIR_FORBID) {
  730.             free(localname);
  731.             return HTLoadError(sink, 403,
  732.             "Directory browsing is not allowed.");
  733.         }
  734.  
  735.  
  736.         if (HTDirAccess == HT_DIR_SELECTIVE) {
  737.             char * enable_file_name = 
  738.             malloc(strlen(localname)+ 1 +
  739.              strlen(HT_DIR_ENABLE_FILE) + 1);
  740.             strcpy(enable_file_name, localname);
  741.             strcat(enable_file_name, "/");
  742.             strcat(enable_file_name, HT_DIR_ENABLE_FILE);
  743.             if (stat(enable_file_name, &file_info) != 0) {
  744.             free(localname);
  745.             return HTLoadError(sink, 403,
  746.             "Selective access is not enabled for this directory");
  747.             }
  748.         }
  749.  
  750.  
  751.         dp = opendir(localname);
  752.         if (!dp) {
  753.             free(localname);
  754.             return HTLoadError(sink, 403, "This directory is not readable.");
  755.         }
  756.  
  757.  
  758.  /*    Directory access is allowed and possible
  759.  */
  760.         logical = HTAnchor_address((HTAnchor*)anchor);
  761.         tail = strrchr(logical, '/') +1;    /* last part or "" */
  762.         
  763.         target = HTML_new(anchor, format_out, sink);
  764.         targetClass = *target->isa;    /* Copy routine entry points */
  765.             
  766.           { int i;
  767.             for(i=0; i<HTML_A_ATTRIBUTES; i++)
  768.                 present[i] = (i==HTML_A_HREF);
  769.         }
  770.         
  771.         {
  772.             char * printable = NULL;
  773.             StrAllocCopy(printable, tail);
  774.             HTUnEscape(printable);
  775.             START(HTML_TITLE);
  776.             PUTS(*printable ? printable : "Welcome ");
  777.             PUTS(" directory");
  778.             END(HTML_TITLE);    
  779.     
  780.             START(HTML_H1);
  781.             PUTS(*printable ? printable : "Welcome");
  782.             END(HTML_H1);
  783.             free(printable);
  784.         }
  785.         
  786.                 if (HTDirReadme == HT_DIR_README_TOP)
  787.             do_readme(target, localname);
  788.         
  789.  
  790. #ifdef SORT
  791.         HTBTree * bt = HTBTree_new(strcasecomp);
  792. #endif
  793.         START(HTML_DIR);        
  794.  
  795.         while (dirbuf = readdir(dp)) {
  796.                 /* while there are directory entries to be read */
  797.             if (dirbuf->d_ino == 0)
  798.                     /* if the entry is not being used, skip it */
  799.             continue;
  800.             
  801.             if (!strcmp(dirbuf->d_name,"."))
  802.             continue;      /* skip the entry for this directory */
  803.             
  804.             if (strcmp(dirbuf->d_name,"..") != 0) {
  805.                 /* if the current entry is parent directory */
  806.             if ((*(dirbuf->d_name)=='.') ||
  807.                 (*(dirbuf->d_name)==','))
  808.                 continue;    /* skip those files whose name begins
  809.                         with '.' or ',' */
  810.             } else {
  811.                 if (!*tail) continue; /* No up from top level */
  812.             }
  813.             StrAllocCopy(tmpfilename,localname);
  814.             if (strcmp(localname,"/")) 
  815.                     /* if filename is not root directory */
  816.             StrAllocCat(tmpfilename,"/"); 
  817.             else
  818.             if (!strcmp(dirbuf->d_name,".."))
  819.                 continue;
  820.         /* if root directory and current entry is parent
  821.                     directory, skip the current entry */
  822.             
  823.             StrAllocCat(tmpfilename,dirbuf->d_name);
  824.             /* append the current entry's filename to the path */
  825.             HTSimplify(tmpfilename);
  826.             
  827.             /* Output the directory entry */
  828.         
  829.             START(HTML_LI);
  830.             {
  831.             char * relative;
  832.             char * escaped = HTEscape(
  833.                 dirbuf->d_name, URL_XPALPHAS);
  834.             /* If empty tail, gives absolute ref below */
  835.             relative = (char*) malloc(
  836.                 strlen(tail) + strlen(escaped)+2);
  837.             if (relative == NULL) outofmem(__FILE__, "DirRead");
  838.             sprintf(relative, "%s/%s", tail, escaped);
  839.             value[HTML_A_HREF] = relative;
  840.             (*targetClass.start_element)(
  841.                     target,HTML_A, present, value);
  842.             free(escaped);
  843.             free(relative);
  844.             }
  845.             stat(tmpfilename, &file_info);
  846.             
  847.             if (strcmp(dirbuf->d_name,"..")) {
  848. /* if the current entry is not the parent directory then use the file name */
  849.             PUTS(dirbuf->d_name);
  850.             if (((file_info.st_mode) & S_IFMT) == S_IFDIR) 
  851.                 PUTC('/'); 
  852.             }                
  853.             else {
  854.             /* use name of parent directory */
  855.             char * endbit = strrchr(tmpfilename, '/');
  856.             PUTS("Up to ");
  857.             PUTS(endbit?endbit+1:tmpfilename);
  858.             }    
  859.             END(HTML_A);
  860.             
  861.         } /* end while directory entries left to read */
  862.         
  863.         closedir(dp);
  864.         free(logical);
  865.         free(tmpfilename);
  866.         
  867. #ifdef SORT
  868.         {        /* Read out sorted filenames */
  869.             void * ele = NULL;
  870.             while ( (ele=HTBTree_next(bt, ele) != 0) {
  871.                if (TRACE) fprintf(stderr,
  872.                    "Sorted: %s\n", HTBTree_object(ele);
  873.             /* @@@@@@@@@@@@@@@@@ */
  874.             }
  875.             HTBTree_free(bt);
  876.         }
  877. #endif        
  878.         END(HTML_DIR);
  879.  
  880.         if (HTDirReadme == HT_DIR_README_BOTTOM)
  881.             do_readme(target, localname);
  882.  
  883.         END_TARGET;
  884.         FREE_TARGET;
  885.             
  886.         free(localname);
  887.         return HT_LOADED;    /* document loaded */
  888.         
  889.         } /* end if localname is directory */
  890.     
  891.     } /* end if file stat worked */
  892.     
  893. /* End of directory reading section
  894. */
  895. #endif
  896. open_file:
  897.     fd = open(localname, O_RDONLY, 0);
  898.     if(TRACE) printf ("HTAccess: Opening `%s' gives %d\n",
  899.                 localname, fd);
  900.     if (fd>=0) {        /* Good! */
  901.         if (HTEditable(localname)) {
  902.             HTAtom * put = HTAtom_for("PUT");
  903.         HTList * methods = HTAnchor_methods(anchor);
  904.         if (HTList_indexOf(methods, put) == (-1)) {
  905.             HTList_addObject(methods, put);
  906.         }
  907.         }
  908.     free(localname);
  909.     }
  910.     }  /* local unix file system */
  911. #endif
  912. #endif
  913.  
  914. #ifdef TRY_WAIS 
  915. /* this just a fallback, mosaic could do this load just as well 
  916.  * the problem is that a bogus url could end up here ? what to do ? BUGBUG 
  917.  * hess 
  918.  */
  919. if (fd<0) {
  920.     char *tryaddr = 0; 
  921.         int status ;
  922.     StrAllocCopy(tryaddr, anchor->address); 
  923.     status = HTLoadWAIS(tryaddr, anchor, format_out, sink);
  924.     free(tryaddr); 
  925.     if( status == HT_LOADED) 
  926.         return HT_LOADED;
  927. }
  928. #endif
  929.  
  930. /*    All attempts have failed if fd<0.
  931. */
  932.     if (fd<0) {
  933.         if (TRACE)
  934.         printf("Can't open `%s', errno=%d\n", addr, errno);
  935.     return HTLoadError(sink, 403, "Can't access requested file.");
  936.     }
  937.     
  938.     HTParseSocket(format, format_out, anchor, fd, sink);
  939.     NETCLOSE(fd);
  940.     return HT_LOADED;
  941.  
  942. }
  943.  
  944. /*        Protocol descriptors
  945. */
  946. PUBLIC HTProtocol HTFile = { "file", HTLoadFile, HTFileSaveStream };
  947.  
  948.